const chars62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

// 检查输入的值是否为空
export function checkNull(val: any) {
  if (val === null || val === undefined || val === '' || typeof val === 'number' && isNaN(val)) {
    return true;
  } else if (Array.isArray(val) && val.length === 0) {
    return true;
  } else {
    return false;
  }
}

// 检查输入的值是否非空
export function checkNotNull(val: any) {
  return !checkNull(val);
}

//获取字符串的字节数
export function strLength(str: string) {
  let count = 0;  //初始化字节数递加变量并获取字符串参数的字符个数
  if (str) {  //如果存在字符串，则执行
    const len = str.length;
    for (let i = 0; i < len; i++) {  //遍历字符串，枚举每个字符
      if (str.charCodeAt(i) > 255) {  //字符编码大于255，说明是双字节字符(即是中文)
        count += 2;  //则累加2个
      } else {
        count++;  //否则递加一次
      }
    }
    return count;  //返回字节数
  } else {
    return 0;  //如果参数为空，则返回0个
  }
}

//自动转换字节的单位，会有两个参数输入到此函数，分别是数量，和一个json对象，对象中有三个属性，分别是保留的小数位数（默认为1），输入的字节是哪种单位（默认为B，没有名为auto的值），输出的字节是哪种单位（默认为auto）
//首先根据输入的数量和输入的字节单位，自动转换成字节数（以B为单位）
//然后根据设置的输出的字节单位，自动转换成对应的字节单位。如果输出的字节单位为auto，则根据输入的字节单位自动转换成合适的字节单位
//最后返回转换后的字符串
export function formatBytes(bytes: number, {
  decimals = 1,
  from = 'B',
  to = 'auto'
} = {}): string {
  //如果输入的bytes为负数的处理
  if (bytes < 0) {
    return '-' + formatBytes(-bytes, {
      decimals,
      from,
      to
    });
  } else if (bytes === 0) {
    return '0 B';
  } else {
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    const i = from === 'auto' ? Math.floor(Math.log(bytes) / Math.log(k)) : sizes.indexOf(from);
    bytes = bytes / Math.pow(k, i);
    if (to === 'auto') {
      const j = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, j)).toFixed(dm)) + ' ' + sizes[j];
    } else {
      return parseFloat((bytes).toFixed(dm)) + ' ' + to;
    }
  }
}


//检查密码强度的函数，会有两个参数输入到此函数，分别是密码，和一个json对象，对象中有几个属性，分别是密码的最小长度（默认为8），密码的最大长度（默认为16），密码中必须包含的字符类型（默认为数字、大小写字母、特殊字符），密码中必须包含的字符类型的最小数量（默认为1），密码中必须包含的字符类型的最大数量（默认为3），密码中必须包含的字符类型的最小数量（默认为2），密码中必须包含的字符类型的最大数量（默认为4）
//首先根据设置的密码的最小长度和密码的最大长度，判断密码的长度是否符合要求
//然后根据设置的密码中必须包含的字符类型，判断密码中是否包含了所有的字符类型
//最后根据设置的密码中必须包含的字符类型的最小数量和密码中必须包含的字符类型的最大数量，判断密码中是否包含了所有的字符类型的最小数量和最大数量
export function checkPassword(password: string, {
  minLength = 8,
  maxLength = 16,
  //字符类型：数字、小写字母、大写字母、特殊字符
  types = ['number', 'lowercase', 'uppercase', 'special'],
  minTypes = 2,
  maxTypes = 4
} = {}) {
  //判断密码的长度是否符合要求
  if (password.length < minLength || password.length > maxLength) {
    return false;
  }
  //判断密码中是否包含了所有的字符类型
  let typesCount = 0;
  if (types.indexOf('number') > -1 && /\d/.test(password)) {
    typesCount++;
  }
  if (types.indexOf('lowercase') > -1 && /[a-z]/.test(password)) {
    typesCount++;
  }
  if (types.indexOf('uppercase') > -1 && /[A-Z]/.test(password)) {
    typesCount++;
  }
  if (types.indexOf('special') > -1 && /[~!@#$%^&*()_+`\-={}:";'<>?,.\/]/.test(password)) {
    typesCount++;
  }
  if (typesCount < minTypes || typesCount > maxTypes) {
    return false;
  }
  return true;
}


//检查是否为Email的函数，会有一个参数输入到此函数，分别是Email
export function checkEmail(email: string) {
  const reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/
  return reg.test(email)
}

//一个62进制的加密函数，将十进制数字转换为62进制字符串
export function encode62(num: number): string {
  let radix = chars62.length;
  let arr: string[] = []; // specify the type of arr as string[]
  do {
    let mod = num % radix;
    num = (num - mod) / radix;
    arr.unshift(chars62[mod]);
  } while (num);
  return arr.join('');
}

//一个62进制的解密函数，将62进制字符串转换为十进制数字
export function decode62(str: string | number): number {
  if (typeof str == 'number') {
    str = str.toString();
  }
  let radix = chars62.length;
  let len = str.length;
  let i = 0;
  let origin = 0;
  while (i < len) {
    origin += Math.pow(radix, i++) * chars62.indexOf(str.charAt(len - i) || '0');
  }
  return Number(origin);
}

//从一个URL字符串中获取文件名
export function getFileNameFromURL(url: string): string {
  let arr = url.split('/');
  return arr[arr.length - 1];
}

//从一个字符串中获取文件后缀格式
export function getFileExtFromString(str: string): string {
  let arr = str.split('.');
  return arr[arr.length - 1];
}

//拼接一个站点的标题，会有一个json对象作为参数输入到此函数，对象中有四个属性，分别是标题（默认为none），站点名称（默认为Galanga），分隔符（默认为-），是否反转（默认为false）
export function spliceSiteTitle({
  title = 'none' as string,
  siteName = 'Galanga' as string,
  separator = '-' as string,
  reverse = false as boolean
} = {}): string {
  separator = ' ' + separator + ' ';
  if (reverse) {
    return siteName + separator + title;
  } else {
    return title + separator + siteName;
  }
}